from datetime import date, timedelta

from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.utils import timezone

from sysreptor.pentests import querysets, storages
from sysreptor.users.models import PentestUser
from sysreptor.utils.configuration import configuration
from sysreptor.utils.crypto import pgp
from sysreptor.utils.crypto.fields import EncryptedField
from sysreptor.utils.models import BaseModel


class UserPublicKey(BaseModel):
    user = models.ForeignKey(to=PentestUser, on_delete=models.CASCADE, related_name='public_keys')
    name = models.CharField(max_length=255)
    enabled = models.BooleanField(default=True, db_index=True)
    public_key = EncryptedField(base_field=models.TextField())
    public_key_info = models.JSONField()

    objects = querysets.UserPublicKeyManager()

    def encrypt(self, data):
        return pgp.encrypt(data=data, public_key=self.public_key)


class ArchivedProject(BaseModel):
    """
    An archived project that is encrypted using shamir secret sharing.
    Each user gets 1 key part.
    The user key part is encrypted with all public keys of this user.
    """
    name = models.CharField(max_length=255, null=False, blank=False, db_index=True)
    tags = ArrayField(base_field=models.CharField(max_length=255), default=list, blank=True, db_index=True)

    threshold = models.PositiveIntegerField()
    file = models.FileField(storage=storages.get_archive_file_storage)

    objects = querysets.ArchivedProjectManager()

    @property
    def auto_delete_date(self) -> date | None:
        if not configuration.AUTOMATICALLY_DELETE_ARCHIVED_PROJECTS_AFTER:
            return None
        out = (self.created  + timedelta(days=configuration.AUTOMATICALLY_DELETE_ARCHIVED_PROJECTS_AFTER)).date()
        if out < timezone.now().date():
            out = timezone.now().date()
        return out


class ArchivedProjectKeyPart(BaseModel):
    archived_project = models.ForeignKey(to=ArchivedProject, on_delete=models.CASCADE, related_name='key_parts')
    user = models.ForeignKey(to=PentestUser, on_delete=models.PROTECT, null=True, blank=False)

    encrypted_key_part = models.BinaryField()
    key_part = EncryptedField(base_field=models.JSONField(null=True, blank=True), null=True, blank=True)
    decrypted_at = models.DateTimeField(null=True, blank=True, db_index=True)

    @property
    def is_decrypted(self) -> bool:
        return bool(self.decrypted_at)


class ArchivedProjectPublicKeyEncryptedKeyPart(BaseModel):
    key_part = models.ForeignKey(to=ArchivedProjectKeyPart, on_delete=models.CASCADE, related_name='public_key_encrypted_parts')
    public_key = models.ForeignKey(to=UserPublicKey, on_delete=models.PROTECT)

    # Shamir key part encrypted by public key
    encrypted_data = EncryptedField(base_field=models.CharField())

